/**
 * GB28181服务监听程序
 */
const parseString = require('xml2js').parseString;
const sip         = require('sip');
const log4js      = require('../data/log');
const logger      = log4js.getLogger('sip');
const constants   = require('../data/constants');
const format      = require('string-format');
const fs          = require('fs');
// 命令都放在这里
const command     = require('./command');

const cameraModel = require('../model/camera');
const deviceModel = require('../model/device');

// 编码转换
const iconv = require('iconv-lite');

/**
 * SIP服务端
 */
const sipServer={
  running:false,
  sipSetting:null,
  stop:function(){
    if(this.running){
      sip.stop();
    }
  },
  restart:function(option){
    this.sipSetting=option;
    if(!this.running){
      this.start(option);
    }
  },
  /**
   * 对外接口，启动 sip 服务端
   */ 
  start : function(option){
    logger.info('启动参数:',option);
    this.sipSetting=option;
    command.config(this.sipSetting);
    let me = this;

    sip.start({
      port: this.sipSetting.sip_command_port,
      udp:  constants.sip.udp,
      tcp:  constants.sip.tcp,
      logger: { 
        send: function(message, address) { 
          let str=format('{status} {headers.cseq.method} from={headers.from.uri} to={headers.to.uri} cseq={headers.cseq.seq}',message);
          logger.info("send:" ,str,'callid=' + message.headers["call-id"] ); 
        },
        recv: function(rq, address) {
          let str = format('{method} {headers.cseq.method} from={headers.from.uri} to={headers.to.uri} cseq={headers.cseq.seq}',rq);
          logger.info("recv:",str,'callid=' + rq.headers["call-id"] ); 
       
          // 不知道为什么有些消息在下面回调怎么取不到，临时放在这里处理
          if(!rq.method){
            switch(rq.status){
              case 100:
                // logger.info('retry');
                break;
              case 200:
                if(rq.headers.cseq.method=='INVITE'){
                  // 回复ack
                  
                  let inviteAck = command.inviteAck(rq);
                  sip.send(inviteAck);
                  
                  let uriObj = command.analysisUri(rq);
                  
                  me.loadCamera(uriObj.deviceid,(obj)=>{
                    if(obj){
                      //TODO: 这个应该不要了
                      constants.registry[uriObj.deviceid].play=true;
                    }
                  });
                }
                break;
              case 400:
                // logger.error('bad request', rq);
                break;
            }
          }
        }
      }
    },
    function(rq) {
      let receiveUri  = sip.parseUri(rq.headers.from.uri);
      let deviceid    = receiveUri.user;
      me.loadCamera(deviceid,function(obj){
        if(obj){
          me.dataHandler(rq,deviceid, me.sipSetting.sip_command_password, me.sipSetting.server_realm);          
        }
      });
    });
    command.sip = sip;
  },
  // 加载设备
  loadCamera:function(deviceid,callback){
    let me = this;
    if(!me.sipSetting){
      return;
    }
    if(constants.registry[deviceid]){
      callback(constants.registry[deviceid]);
    }else{
       // 从数据库加载
       cameraModel.getCameraByName(deviceid,(obj)=>{
        constants.registry[deviceid] ={
          online:true,
          play:false,
          session:{realm:me.sipSetting.server_realm},
          password:me.sipSetting.sip_command_password
        };
        if(obj.length>0){
          constants.registry[deviceid] = Object.assign(constants.registry[deviceid], obj[0]);
        }
        if(!constants.registry[deviceid].version) constants.registry[deviceid].version = constants.sip.version;
        if(!constants.registry[deviceid].sumnum)  constants.registry[deviceid].sumnum=1;
        callback(constants.registry[deviceid]);
      });
    }
  },
  // 消息分流处理
  dataHandler:function(rq,deviceid,sip_command_password,server_realm){
    if(!rq.method){
      // method为空的放到logger的recv里处理了
      return;
    }
    let uriObj    = command.analysisUri(rq);
    //logger.debug('dataHandler===============',rq,rq.headers.via[0]);
    if(rq.method ==='REGISTER') {
      // 收到注册消息
      if(rq.headers.authorization){
        logger.info('authorization[0]=',rq.headers.authorization[0]);
      }
      
      // 生成用户信息
      constants.registry[deviceid] = {
        password  : sip_command_password,
        online    : false,
        deviceid  : deviceid,
        session   : {
          realm   : server_realm
        },
        sip_command_host  : uriObj.sip_command_host,
        sip_command_port  : uriObj.sip_command_port,
        play      : false, // 是否在播放     
        uri       : uriObj.uri,
        protocol  : rq.headers.via[0].protocol ? rq.headers.via[0].protocol : 'UDP'
      };

      // 回复注册请求
      let registerAck = command.registerAck(rq);
      logger.info('registerack',registerAck.headers.via[0]);
      sip.send(registerAck);

      // 如果通过校验
      if(registerAck.status==200){
        constants.registry[deviceid].contact = rq.headers.contact;
        constants.registry[deviceid].online=true;

        // 记录到数据库
        cameraModel.updateOnline(deviceid,()=>{
          let catalogCmd = command.catalog(constants.registry[deviceid]);
          // 发送更新目录命令
          sip.send(catalogCmd);
          // 更新额外信息
          cameraModel.update({
            deviceid  : deviceid,
            sip_command_host : uriObj.sip_command_host,
            sip_command_port : uriObj.sip_command_port
          },null);
        });
      }
    }

    else if(rq.method==='MESSAGE'){
      // 收到其它消息
      parseString(rq.content,(err,result)=>{
        if(result.Notify){
          let CmdType = result.Notify.CmdType[0];
          switch(CmdType){
            case 'Keepalive':
              // 心跳
              // 对指定device更新状态
              deviceModel.updateOnline(deviceid,result.Notify.DeviceID,1).then(()=>{
                let alive = command.keepalive(rq);
                sip.send(alive);
              }).catch((e)=>{
                log.error(e);
              });
              break;
            case 'Catalog':
              // 定时刷新catalog状态
              let deviceIds = result.Notify.DeviceID;
              for(var s in deviceIds){
                // 编码转换
                deviceModel.updateOnline(deviceid,deviceIds[s],1).catch((e)=>{
                  log.error(e);
                });
              }
              sip.send(sip.makeResponse(rq,200,'OK'));
              break;
            default:
              logger.error('未解析的指令',CmdType);
          }
        }else if(result.Response){
          // logger.info('重点看这个数据',result.Response);
          let CmdType = result.Response.CmdType.toString();
          
          sip.send(sip.makeResponse(rq,200,'OK'));
          // sip.stop();
          // 收到设备列表后回复
          switch(CmdType){
            case "Catalog":
              // 通道数量 
              let sumnum = result.Response.SumNum.toString();
              constants.registry[deviceid].sumnum=sumnum;
              if(!constants.registry[deviceid].channels){
                constants.registry[deviceid].channels={};
              }

              cameraModel.updateOnline(deviceid,function(){
                for(let s in result.Response.DeviceList){
                  let temp = result.Response.DeviceList[0].Item[s];
                  if(!temp.DeviceID.toString()){
                    continue;
                  }
                  if(temp.Name.toString()){
                    let bufs = iconv.decode(temp.Name.toString(), 'gb2312');
                    //转为utf8
                    temp.Name = [bufs.toString('utf8')];
                  }

                  let channelId=temp.DeviceID.toString();
                  if(!constants.registry[deviceid].channels[channelId]){
                    constants.registry[deviceid].channels[channelId]=Object.assign({},constants.registry[deviceid]);
                    constants.registry[deviceid].channels[channelId].deviceid=temp.DeviceID.toString();
                    constants.registry[deviceid].channels[channelId].uri=constants.registry[deviceid].channels[channelId].uri.replace(deviceid,channelId);
                    constants.registry[deviceid].channels[channelId].parentid=deviceid;
                  }
                 
                  deviceModel.updateInfo(temp,1).catch((e)=>{
                    logger.error(e);
                  });
                }
              });
              break;
            default:
              break;
          }
        }
      });
    }
    else if(rq.method=='ACK'){
      logger.info('TODO: ack',rq);
    }
    else if(rq.method=='BYE'){
      let ack = command.byeAck(rq);
      sip.send(ack);
    }
    else {
      logger.debug('TODO:', rq.method);
      sip.send(sip.makeResponse(rq, 405, 'Method Not Allowed'));
    }
  },
  /**
   * 对外接口
   * @param {发邀请目标} target 
   */
  invite:function(deviceid,channel,udpPort,callback){
    this.loadCamera(deviceid,(obj)=>{
      if(obj){
        let cmd = command.invite(deviceid,channel,udpPort);
        logger.info('invite cmd',cmd);
        if(!cmd){
          callback(false);
        }else{
          sip.send(cmd);
          callback(true);
        }
      }else{
        logger.error('TODO:404 设备不存在');
      }
    });
  },
  bye:function(deviceid,channel,callback){
    this.loadCamera(deviceid,(obj)=>{
      if(obj){
        let cmd = command.bye(deviceid,channel);
        logger.info('bye cmd',cmd);
        if(!cmd){
          callback(false);
        }else{
          sip.send(cmd);
          callback(true);
        }
      }else{
        logger.error('TODO:404 设备不存在');
      }
    });
  },
  catalog:function(deviceid){
    this.loadCamera(deviceid,(obj)=>{
      if(obj){
        logger.info('看看这时obj的值',deviceid,obj,constants.registry[deviceid]);
        let catalogCmd = command.catalog(constants.registry[deviceid]);
        logger.info('计算的catalogCmd',catalogCmd);
        if(catalogCmd){
          sip.send(catalogCmd);
        }
      }else{
        logger.error('TODO:404 设备不存在');
      }
    });
  },
  /**
   * TODO: 轮循有没有过期的
   * 国标定义，平台收不到心跳超过3次则判定设备离线，设备收不到心跳反馈3次则重新注册
   */
  keepalive:function(){
    let me = this;
    setInterval(function(){
      for(var key in constants.registry){
        if(constants.registry[key].online){
          let diff = ((new Date()).getTime() - constants.registry[key].last)/1000;
          if(diff > me.sipSetting.keepalive*3){
            constants.registry[key].online=false;
          }
        }
      }
    },me.sipSetting.keep_alive_second * 1000);
  }
}

module.exports = sipServer;
